'''
Created on Nov 22, 2010

@author: dexen
'''

import cPickle

from dexen.system.common.meta import TaskMeta



#===============================================================================
# Slave States
#===============================================================================
S_BUSY = "SlaveBusy"
S_CRASHED = "SlaveCrashed"
S_IDLE = "SlaveIdle"

#===============================================================================
# Task States
#===============================================================================
T_FAIL = "TaskFail"
T_SUCCESS = "TaskSuccess"


#===============================================================================
# Transactions
#===============================================================================
class Transaction(object):
    def __init__(self, id, inds=[]):
        self.id = id
        self.inds = cPickle.dumps(inds)

    def strip_inds(self):
        from dexen.system.common.base import Individual
        inds = cPickle.loads(self.inds)
        stripped_inds = []
        for ind in inds:
            assert isinstance(ind, Individual)
            stripped_inds.append(ind.__stripped_clone__())
        self.inds = cPickle.dumps(stripped_inds)

    def get_inds(self):
        return cPickle.loads(self.inds)

    def set_inds(self, inds):
        self.inds = cPickle.dumps(inds)

    def __repr__(self):
        out = "Id: {0}\n".format(self.id)
        out += "Ind Size: {0}\n".format(len(self.get_inds()))
        return out

    @classmethod
    def get_header(self):
        return "TransId,Task,Node  ,Outcome,ExecTime"
            

class SlaveTransact(object):
    def __init__(self, task_meta, slave_name=None):
        self.task_meta = task_meta
        self.slave_name = slave_name

    def get_task_name(self):
        task_meta = self.task_meta
        assert isinstance(task_meta, TaskMeta)
        return task_meta.get_name()
    
    def get_task_label(self):
        task_meta = self.task_meta
        assert isinstance(task_meta, TaskMeta)
        return task_meta.get_label()
        
    def get_task_meta(self):
        return self.task_meta

    def set_slave_name(self, slave_name):
        self.slave_name = slave_name

    def create_slave_recv_transact(self):
        return SlaveRecvTransact(self.id, self.task_meta, self.slave_name)

    def __repr__(self):
        out = "Slave Name: {0}\n".format(self.slave_name)
        out += "Task Name: {0}\n".format(self.get_task_name())
        return out

class RecvTransact(object):
    def __init__(self):
        self.out_msg = None
        self.err_msg = None
        self.exec_time = None
        self.outcome = None

    def get_exec_time(self):
        return self.exec_time
    
    def set_exec_time(self, exec_time):
        self.exec_time = exec_time
    
    def set_err_msg(self, msg):
        self.err_msg = msg
       
    def get_err_msg(self):
        return self.err_msg
    
    def set_out_msg(self, msg):
        self.out_msg = msg
    
    def get_out_msg(self):
        return self.out_msg

    def task_succeeded(self):
        self.outcome = T_SUCCESS
    
    def task_failed(self):
        self.outcome = T_FAIL

    def has_task_failed(self):
        return self.outcome == T_FAIL
    
    def has_task_succeeded(self):
        return self.outcome == T_SUCCESS        

    def __repr__(self):
        out = "---------- Task Stdout -----------\n"
        out += "{0}\n".format(self.out_msg)
        out += "---------- Task Stderr -----------\n"
        out += "{0}\n".format(self.err_msg)
        return out    

        
class SlaveSendTransact(Transaction, SlaveTransact):
    def __init__(self, id, task_meta, inds):
        Transaction.__init__(self, id, inds)
        SlaveTransact.__init__(self, task_meta)
   
    def get_log(self):
        return "{0},SEND:{1},{2},Pending,None".format(self.id, self.get_task_label(), self.slave_name)

    def __repr__(self):
        out = "------- SlaveSendTransaction ---------\n"
        out += Transaction.__repr__(self)
        out += SlaveTransact.__repr__(self)
        out += "----------------------------------\n"
        return out

    
class SlaveRecvTransact(Transaction, SlaveTransact, RecvTransact):
    def __init__(self, id, task_meta, slave_name):
        Transaction.__init__(self, id)
        SlaveTransact.__init__(self, task_meta, slave_name)
        RecvTransact.__init__(self)
 
    def combine(self, transact):
        from dexen.system.common.base import Individual
        assert isinstance(transact, SlaveSendTransact)
        sent_inds = transact.get_inds()
        recv_inds = self.get_inds()
        recv_ids = [ind.__id__ for ind in recv_inds]
        combined_inds = recv_inds
        for ind in sent_inds:
            assert isinstance(ind, Individual)
            if ind.__id__ not in recv_ids:
                combined_inds.append(ind)
        self.set_inds(combined_inds)
 
    def slave_crashed(self):
        self.outcome = S_CRASHED

    def has_slave_crashed(self):
        return self.outcome == S_CRASHED
        
    def get_log(self):
        return "{0},RECV:{1},{2},{3},{4:.2} secs".format(self.id, self.get_task_label(),
                                                    self.slave_name, self.outcome, self.exec_time)
      
    def __repr__(self):
        out = "------- SlaveRecvTransaction ---------\n"
        out += Transaction.__repr__(self)
        out += SlaveTransact.__repr__(self)
        out += RecvTransact.__repr__(self)
        out += "----------------------------------\n"
        return out
    
        
#===============================================================================
# Master Transact
#===============================================================================
class MasterRecvTransact(Transaction, RecvTransact):
    def __init__(self, id, inds=None):
        Transaction.__init__(self, id, inds)
        RecvTransact.__init__(self)
        self._archived = {}

    def get_archive(self):
        return self._archived
    
    def set_archive(self, archived):
        self._archived = archived

    def strip_archive(self):
        self._archived = {}

    def get_log(self):
        return "{0},MasterTask,MASTER,{1},{2:.2} secs".format(self.id, self.outcome, self.exec_time)
      
    def __repr__(self):
        out = "------- MasterRecvTransaction ---------\n"
        out += Transaction.__repr__(self)
        out += RecvTransact.__repr__(self)
        out += "----------------------------------\n"
        return out   
        
